package com.xyht.sca_s.student_manage_system.modules.bigData.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.bigData.entity.req.SmsTeacherPowerBatchReq;
import com.xyht.sca_s.student_manage_system.modules.bigData.entity.resp.*;
import com.xyht.sca_s.student_manage_system.modules.bigData.service.SmsTeachersPowerService;
import com.xyht.sca_s.student_manage_system.modules.clockIn.entity.SmsClockIn;
import com.xyht.sca_s.student_manage_system.modules.clockIn.mapper.SmsClockInMapper;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.teacher.entity.SmsTeacherInfo;
import com.xyht.sca_s.student_manage_system.modules.teacher.entity.SmsUserTeacherRelation;
import com.xyht.sca_s.student_manage_system.modules.teacher.mapper.SmsTeacherAwardMapper;
import com.xyht.sca_s.student_manage_system.modules.teacher.mapper.SmsTeacherInfoMapper;
import com.xyht.sca_s.student_manage_system.modules.teacher.mapper.SmsUserTeacherRelationMapper;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.bigData.constant.AttendanceTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.clockIn.constant.ClockInStateConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample.TASK_NAME_TEACHER_POWER;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant.TASK_TYPE_TEACHER_POWER;

/**
 * <p>
 * 师资力量
 * </p>
 *
 * @author XYHT
 * @since 2023-08-31
 */
@Service
public class SmsTeachersPowerServiceImpl implements SmsTeachersPowerService {

    @Resource
    private SmsTeacherInfoMapper smsTeacherInfoMapper;
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    private SmsTeacherAwardMapper smsTeacherAwardMapper;
    @Resource
    private SmsClockInMapper smsClockInMapper;
    @Resource
    private SmsUserTeacherRelationMapper smsUserTeacherRelationMapper;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private PlatformTransactionManager transactionManager;


    @Override
    @Async
    public Future<ResponseResult> batchAddTeachersPower(Map<String, Object> map, String user_id) {
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map));
        List<SmsTeacherPowerBatchReq> teacherPowerBatchReqs = JSONObject.parseArray(JSON.toJSONString(jsonObject.get("list")), SmsTeacherPowerBatchReq.class);
        if (teacherPowerBatchReqs == null || teacherPowerBatchReqs.size() < 1) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        for (SmsTeacherPowerBatchReq teacherPowerBatchReq : teacherPowerBatchReqs) {
            List<SmsTeacherInfo> smsTeacherInfos = smsTeacherInfoMapper.selectList(new LambdaQueryWrapper<SmsTeacherInfo>()
                    .eq(SmsTeacherInfo::getTchNo, teacherPowerBatchReq.getTchNo()));
            if(smsTeacherInfos == null || smsTeacherInfos.size() < 1){
                return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.TEACHER_NOT_EXIST));
            }
        }
        //创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_TEACHER_POWER);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_TEACHER_POWER);
        smsImportTaskMapper.insert(smsImportTask);
        batchAddTeachersPowerInfo(teacherPowerBatchReqs, smsImportTask.getId());
        return new AsyncResult<>(CommonResult.success());
    }

    private void batchAddTeachersPowerInfo(List<SmsTeacherPowerBatchReq> teacherPowerBatchReqs, String id) {

        int OFFSET_ROW = 1;
        int task_status = TASK_STATUS_DONE;
        for (int i = 0; i < teacherPowerBatchReqs.size(); i++) {
            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);
            try {
                SmsTeacherPowerBatchReq storage = teacherPowerBatchReqs.get(i);
                if (isNullOrEmpty(storage.getTchNo(),storage.getTchName())) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }
                SmsTeacherInfo updateTeacherInfo = new SmsTeacherInfo();
                BeanUtils.copyProperties(storage, updateTeacherInfo);
                if(!isNullOrEmpty(storage.getTchBirth())){
                    Date birth = TimeUtil.StringtoDate(storage.getTchBirth());
                    if(isNullOrEmpty(birth)){
                        transactionManager.rollback(status);
                        task_status = TASK_STATUS_ERR;
                        createTeacherImportTaskDetail(id, REASON_TEACHER_POWER_BIRTH_FORMAT_ERROR, (i + OFFSET_ROW) + "");
                        continue;
                    }
                    updateTeacherInfo.setTchBirth(birth);
                }

                smsTeacherInfoMapper.update(updateTeacherInfo,new LambdaQueryWrapper<SmsTeacherInfo>()
                .eq(SmsTeacherInfo::getTchNo,storage.getTchNo()));
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                task_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            }finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                }
            }
        }
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setId(id);
        smsImportTask.setStatus(task_status);
        smsImportTaskMapper.updateById(smsImportTask);
    }

    private void createTeacherImportTaskDetail(String id, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(id);
        smsImportTaskDetail.setFailReason(reason);
        smsImportTaskDetail.setFailRow(row);
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }

    @Override
    public ResponseResult getTeachersPower() {
        SmsTeachersPowerResp smsTeachersPowerResp = new SmsTeachersPowerResp();
        List<SmsTeacherEducationResp> smsTeacherEducationList = new ArrayList<>();
        List<SmsTeachersSumResp> smsTeachersSumList = new ArrayList<>();
        List<SmsTeacherAwardInfoResp> smsTeacherAwardInfoList;
        //教师学历 数量
        List<Map<String, Object>> maps = smsTeacherInfoMapper.selectMaps(new QueryWrapper<SmsTeacherInfo>()
                .select("count(*) as tchSum,tch_education as tchEducation")
                .lambda()
                .groupBy(SmsTeacherInfo::getTchEducation));
        if(maps != null && maps.size() > 0){
            for (Map<String, Object> map : maps) {
                SmsTeacherEducationResp smsTeacherEducationResp = new SmsTeacherEducationResp();
                SmsTeacherEducationResp smsTeacherEducation = JSONObject.parseObject(JSONObject.toJSONString(map), SmsTeacherEducationResp.class);
                if(!isNullOrEmpty(smsTeacherEducation)){
                    if(!isNullOrEmpty(smsTeacherEducation.getTchEducation())) {
                        smsTeacherEducationResp.setTchEducation(smsTeacherEducation.getTchEducation());
                        smsTeacherEducationResp.setTchSum(smsTeacherEducation.getTchSum());
                        smsTeacherEducationList.add(smsTeacherEducationResp);
                    }
                }
            }
        }
        smsTeachersPowerResp.setTeacherEducation(smsTeacherEducationList);

        //教师职称 数量
        List<Map<String, Object>> tchTitleMaps = smsTeacherInfoMapper.selectMaps(new QueryWrapper<SmsTeacherInfo>()
                .select("count(*) as tchSum,tch_title as tchTitle")
                .lambda()
                .groupBy(SmsTeacherInfo::getTchTitle));
        if(maps != null && maps.size() > 0){
            for (Map<String, Object> map : tchTitleMaps) {
                SmsTeachersSumResp smsTeachersSumResp = new SmsTeachersSumResp();
                SmsTeachersSumResp smsTeachersSum = JSONObject.parseObject(JSONObject.toJSONString(map), SmsTeachersSumResp.class);
                if(smsTeachersSum != null){
                    if(!isNullOrEmpty(smsTeachersSum.getTchTitle())) {
                        smsTeachersSumResp.setTchTitle(smsTeachersSum.getTchTitle());
                        smsTeachersSumResp.setTchSum(smsTeachersSum.getTchSum());
                        smsTeachersSumList.add(smsTeachersSumResp);
                    }
                }
            }
        }
        smsTeachersPowerResp.setTeacherSum(smsTeachersSumList);

        //教师获奖信息
        smsTeacherAwardInfoList = smsTeacherAwardMapper.selectList(null)
                .stream()
                .map(smsTeacherAward -> {
                    SmsTeacherAwardInfoResp smsTeacherAwardInfoResp = new SmsTeacherAwardInfoResp();
                    BeanUtils.copyProperties(smsTeacherAward,smsTeacherAwardInfoResp);
                    List<SmsTeacherInfo> smsTeacherInfoList = smsTeacherInfoMapper.selectList(new LambdaQueryWrapper<SmsTeacherInfo>()
                            .eq(SmsTeacherInfo::getTchNo, smsTeacherAward.getTchNo()));
                    if(smsTeacherInfoList != null && smsTeacherInfoList.size() > 0) {
                        SmsTeacherInfo smsTeacherInfo = smsTeacherInfoList.get(0);
                        SmsUserTeacherRelation smsUserTeacherRelations = smsUserTeacherRelationMapper.selectList(new LambdaQueryWrapper<SmsUserTeacherRelation>()
                                    .eq(SmsUserTeacherRelation::getTchId, smsTeacherInfo.getId())).get(0);
                            if (!isNullOrEmpty(smsUserTeacherRelations)) {
                                SmsUser userInfo = cacheUtil.getUserInfo(smsUserTeacherRelations.getUserId());
                                if (isNullOrEmpty(userInfo)) {
                                    smsTeacherAwardInfoResp.setTchPic(userInfo.getUserPic());
                                }
                            }

                    }
                    List<SmsTeacherInfo> smsTeacherInfos = smsTeacherInfoMapper.selectList(new LambdaQueryWrapper<SmsTeacherInfo>()
                            .eq(SmsTeacherInfo::getTchNo, smsTeacherAward.getTchNo()));
                    if(smsTeacherInfos != null && smsTeacherInfos.size() > 0) {
                        SmsTeacherInfo teacherInfo = smsTeacherInfos.get(0);
                        smsTeacherAwardInfoResp.setTchTitle(teacherInfo.getTchTitle());
                        String tchIdCard = teacherInfo.getTchIdCard();
                        if (!isNullOrEmpty(tchIdCard)) {
                            //获取出生年月日
                            String birthYear = tchIdCard.substring(6, 10);
                            String monthDay = tchIdCard.substring(10, 14);
                            //获取当前时间字符串如：2022-1128
                            String nowTimeStr = new SimpleDateFormat("yyyy-MMdd").format(new Date());
                            String yearNow = nowTimeStr.substring(0, 4);// 当前年份
                            String monthDayNow = nowTimeStr.substring(5, 9);// 当前月日
                            int age = Integer.parseInt(yearNow) - Integer.parseInt(birthYear);
                            //age减一的情况 ：用户月日大于当前月日（开头可以为0的4位数int）
                            if (Integer.parseInt(monthDay) > Integer.parseInt(monthDayNow)) {
                                age = age - 1;
                            }
                            smsTeacherAwardInfoResp.setTchAge(age);
                        }
                    }
                    return smsTeacherAwardInfoResp;
                })
                .collect(Collectors.toList());
        smsTeachersPowerResp.setTeacherAward(smsTeacherAwardInfoList);
        return CommonResult.success(smsTeachersPowerResp);
    }

    @Override
    public ResponseResult getAttendanceOverview(Integer type,Integer pageNum,Integer pageSize) {
        if(isNullOrEmpty(type)){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        Page<SmsClockIn> page = new Page<>(pageNum,pageSize);
        SmsAttendanceOverviewResp smsAttendanceOverviewResp = new SmsAttendanceOverviewResp();
        List<SmsAttendanceInfoResp> smsAttendanceInfoList = new ArrayList<>();
        QueryWrapper<SmsClockIn> sumQueryWrapper = new QueryWrapper<>();
        QueryWrapper<SmsClockIn> normalQueryWrapper = new QueryWrapper<>();
        QueryWrapper<SmsClockIn> leaveEarlyQueryWrapper = new QueryWrapper<>();
        QueryWrapper<SmsClockIn> lateQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<SmsClockIn> queryWrapperList = new LambdaQueryWrapper<>();
        queryWrapperList.orderByDesc(SmsClockIn::getClockInDate);
        smsClockInMapper.selectPage(page,queryWrapperList);
        smsAttendanceInfoList = page.getRecords()
                .stream()
                .map(smsClockIn -> {
                    SmsAttendanceInfoResp smsAttendanceInfoResp = new SmsAttendanceInfoResp();
                    //打卡状态
                    smsAttendanceInfoResp.setClockType(smsClockIn.getClockInType());
                    String userId = smsClockIn.getUserId();
//                    List<SmsUserTeacherRelation> smsUserTeacherRelations = smsUserTeacherRelationMapper.selectList(new LambdaQueryWrapper<SmsUserTeacherRelation>()
//                            .eq(SmsUserTeacherRelation::getUserId, userId));
//                    //有教师角色就以老师姓名
//                    if(smsUserTeacherRelations != null && smsUserTeacherRelations.size() > 0){
//                        SmsUserTeacherRelation smsUserTeacherRelation = smsUserTeacherRelations.get(0);
//                        SmsTeacherInfo teacherInfo = smsTeacherInfoMapper.selectById(smsUserTeacherRelation.getTchId());
//                        //教师姓名
//                        if(teacherInfo != null){
//                            smsAttendanceInfoResp.setTeacherName(teacherInfo.getTchName());
//                        }
//                        //没有教师角色就用用户名字
//                    }else {
                    SmsUser smsUser = cacheUtil.getUserInfo(userId);
                    //教师姓名
                    if (smsUser != null) {
                        smsAttendanceInfoResp.setTeacherName(smsUser.getRealName());
                    }
//                    }

                    //打卡时间
                    Date clockInDate = smsClockIn.getClockInDate();
                    String clockInDateStr = TimeUtil.DateFormatSting(clockInDate);
                    Date clockInTime = smsClockIn.getClockInTime();
                    if(clockInTime != null){
                        String clockInTimeStr = TimeUtil.TimeFormatSting(clockInTime);
                        smsAttendanceInfoResp.setClockTime(clockInDateStr + clockInTimeStr);
                    }else {
                        smsAttendanceInfoResp.setClockTime(clockInDateStr);
                    }
                    return smsAttendanceInfoResp;
                })
                .collect(Collectors.toList());
        smsAttendanceOverviewResp.setAttendanceInfo(smsAttendanceInfoList);

        //本月
        if(type == MONTH_TYPE){
            //转化格式
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            //查传入这个月的一号
            cal.set(Calendar.DAY_OF_MONTH, 1);
            String firstDate = TimeUtil.DateFormatSting(cal.getTime());
            //查传入这个月的最后一号
            cal.roll(Calendar.DAY_OF_MONTH, -1);
            String endDate = TimeUtil.DateFormatSting(cal.getTime());
            //出勤总人数
            sumQueryWrapper
                    .select("DISTINCT user_id")
                    .lambda()
                    .ge(SmsClockIn::getClockInDate, firstDate)
                    .le(SmsClockIn::getClockInDate, endDate);
            //满勤数量
            normalQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .ne(SmsClockIn::getClockInState,CLOCK_IN_STATE_NORMAL)
                    .ge(SmsClockIn::getClockInDate, firstDate)
                    .le(SmsClockIn::getClockInDate, endDate)
                    .groupBy(SmsClockIn::getUserId);

            //早退数量
            leaveEarlyQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LEAVE_EARLY)
                    .ge(SmsClockIn::getClockInDate, firstDate)
                    .le(SmsClockIn::getClockInDate, endDate)
                    .groupBy(SmsClockIn::getUserId);

            //迟到数量
            lateQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LATE)
                    .ge(SmsClockIn::getClockInDate, firstDate)
                    .le(SmsClockIn::getClockInDate, endDate)
                    .groupBy(SmsClockIn::getUserId);

        //本季度
        } else if (type == QUARTER_TYPE) {
            //出勤总人数
            sumQueryWrapper
                    .select("DISTINCT user_id")
                    .apply("QUARTER(clock_in_date) = QUARTER(NOW())");

            //满勤数量
            normalQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .ne(SmsClockIn::getClockInState,CLOCK_IN_STATE_NORMAL)
                    .apply("QUARTER(clock_in_date) = QUARTER(NOW())")
                    .groupBy(SmsClockIn::getUserId);

            //早退数量
            leaveEarlyQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LEAVE_EARLY)
                    .apply("QUARTER(clock_in_date) = QUARTER(NOW())")
                    .groupBy(SmsClockIn::getUserId);

            //迟到数量
            lateQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LATE)
                    .apply("QUARTER(clock_in_date) = QUARTER(NOW())")
                    .groupBy(SmsClockIn::getUserId);

        //本年
        } else if (type == YEAR_TYPE) {
            //出勤总人数
            sumQueryWrapper
                    .select("DISTINCT user_id")
                    .apply("YEAR(clock_in_date)=YEAR(NOW())");
            //满勤数量
            normalQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .ne(SmsClockIn::getClockInState,CLOCK_IN_STATE_NORMAL)
                    .apply("YEAR(clock_in_date)=YEAR(NOW())")
                    .groupBy(SmsClockIn::getUserId);

            //早退数量
            leaveEarlyQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LEAVE_EARLY)
                    .apply("YEAR(clock_in_date)=YEAR(NOW())")
                    .groupBy(SmsClockIn::getUserId);

            //迟到数量
            lateQueryWrapper
                    .select("count(user_id)")
                    .lambda()
                    .eq(SmsClockIn::getClockInState,CLOCK_IN_STATE_LATE)
                    .apply("YEAR(clock_in_date)=YEAR(NOW())")
                    .groupBy(SmsClockIn::getUserId);

        }
        List<SmsClockIn> sumClockIns = smsClockInMapper.selectList(sumQueryWrapper);
        List<SmsClockIn> normalClockIns = smsClockInMapper.selectList(normalQueryWrapper);
        List<SmsClockIn> leaveEarlyClockIns = smsClockInMapper.selectList(leaveEarlyQueryWrapper);
        List<SmsClockIn> lateClockIns = smsClockInMapper.selectList(lateQueryWrapper);
        int clockInSum = sumClockIns == null ? 0 : sumClockIns.size();
        int normalSum = normalClockIns == null ? clockInSum : (clockInSum - normalClockIns.size());
        int leaveEarlySum = leaveEarlyClockIns == null ? 0 : leaveEarlyClockIns.size();
        int lateSum = lateClockIns == null ? 0 : lateClockIns.size();
        //满勤数量
        smsAttendanceOverviewResp.setFullAttendanceSum(normalSum);
        //早退数量
        smsAttendanceOverviewResp.setLeaveEarlySum(leaveEarlySum);
        //迟到数量
        smsAttendanceOverviewResp.setLateSum(lateSum);
        //占比
        if(clockInSum == 0){
            smsAttendanceOverviewResp.setFullAttendanceRatio(0);
            smsAttendanceOverviewResp.setLeaveEarlyRatio(0);
            smsAttendanceOverviewResp.setLateSumRatio(0);
        }else {
            double fullAttendanceRatio = Math.ceil((double) normalSum / clockInSum * 100);
            double leaveEarlyRatio = Math.floor((double) leaveEarlySum / clockInSum * 100);
            double lateSumRatio = 100 - fullAttendanceRatio - leaveEarlyRatio;
            //满勤占比
            smsAttendanceOverviewResp.setFullAttendanceRatio((int)fullAttendanceRatio);
            //早退占比
            smsAttendanceOverviewResp.setLeaveEarlyRatio((int)leaveEarlyRatio);
            //迟到占比
            smsAttendanceOverviewResp.setLateSumRatio((int)lateSumRatio);
        }
        return CommonResult.success(smsAttendanceOverviewResp);
    }
}
